<template>
  <div>
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item
        ><a href="/admin" @click="resetDefaultActivePath"
          >首页</a
        ></el-breadcrumb-item
      >
      <el-breadcrumb-item>用户管理</el-breadcrumb-item>
      <el-breadcrumb-item>用户列表</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 内容卡片区域 -->
    <el-card class="box-card">
      <el-row>
        <el-col :span="18">
          <el-form :inline="true" :model="searchData" class="demo-form-inline">
            <el-form-item label="">
              <el-select v-model="searchData.role" placeholder="-所有角色-">
                <el-option label="管理员" value="manger"></el-option>
                <el-option label="普通用户" value="normal"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="">
              <el-select v-model="searchData.origin" placeholder="-所有来源-">
                <el-option label="本地注册" value="local"></el-option>
                <el-option label="Github登录" value="github"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="">
              <el-select v-model="searchData.type" placeholder="-所有用户-">
                <el-option label="用户名" value="username"></el-option>
                <el-option label="邮箱" value="email"></el-option>
                <el-option label="手机" value="phone"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="">
              <el-input
                v-model="searchData.key"
                placeholder="关键字"
              ></el-input>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="el-icon-search" @click="onSubmit"
                >查询</el-button
              >
              <el-button type="primary" icon="el-icon-share" @click="exportUser"
                >导出搜索结果</el-button
              >
            </el-form-item>
          </el-form>
        </el-col>
        <el-col :span="6">
          <el-button type="primary" @click="showDialog">添加用户</el-button>
          <el-upload
            class="upload-demo"
            action="http://127.0.0.1:7001/api/v1/importUser/"
            :show-file-list="false"
            :on-success="handleExcelSuccess"
            :before-upload="beforeExcelUpload"
            accept=".xlsx"
          >
            <el-button type="primary">
              <i class="el-icon-upload el-icon--left"></i>
              导入用户
            </el-button>
          </el-upload>
          <a
            href="http://127.0.0.1:7001/api/v1/exportUser/"
            class="upload-demo"
          >
            <el-button type="primary">
              <i class="el-icon-upload el-icon--left"></i>
              导出用户
            </el-button>
          </a>
        </el-col>
      </el-row>
      <!-- 中间表格区域 -->
      <el-table :data="tableData" border stripe style="width: 100%">
        <el-table-column label="序号" width="75">
          <template #default="{ $index }">
            {{
              (searchData.currentPage - 1) * searchData.pageSize + $index + 1
            }}
          </template>
        </el-table-column>
        <el-table-column prop="name" label="名称"> </el-table-column>
        <el-table-column prop="username" label="用户名"> </el-table-column>
        <el-table-column prop="email" label="邮箱"> </el-table-column>
        <el-table-column prop="phone" label="电话"> </el-table-column>
        <!-- 利用formatter去处理角色名称的显示 -->
        <el-table-column :formatter="getCurrentRoleName" label="角色">
        </el-table-column>
        <el-table-column label="状态">
          <!-- 使用作用域插槽拿到当前这一行的数据 -->
          <template slot-scope="{ row }">
            <el-switch
              v-model="row.userState"
              active-color="#13ce66"
              inactive-color="#ff4949"
              @change="changeUserState(row)"
            >
            </el-switch>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template slot-scope="{ row }">
            <el-button
              type="primary"
              icon="el-icon-edit"
              @click="showUser(row.id)"
            ></el-button>
            <el-button
              type="danger"
              @click="deleteUser(row.id)"
              icon="el-icon-delete"
            ></el-button>
            <el-tooltip
              class="item"
              effect="dark"
              content="分配角色"
              placement="top"
              :enterable="false"
            >
              <el-button
                type="warning"
                @click="addRole(row)"
                icon="el-icon-setting"
              ></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <!-- 底部分页区域 -->
      <el-pagination
        style="text-align: center; padding-top: 20px"
        :current-page="searchData.currentPage"
        :page-sizes="[5, 10, 15, 20]"
        :page-size="searchData.pageSize"
        :total="total"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      >
      </el-pagination>
    </el-card>
    <!-- 添加和编辑的对话框 -->
    <el-dialog
      :title="userData.id ? '编辑用户' : '添加用户'"
      :visible.sync="dialogVisible"
      width="30%"
      @close="close"
    >
      <el-form
        ref="formData"
        :model="userData"
        :rules="userRules"
        label-width="58px"
      >
        <el-form-item label="" style="text-align: center">
          <el-upload
            class="avatar-uploader"
            action="http://127.0.0.1:7001/api/v1/posts/"
            :show-file-list="false"
            :on-success="handleAvatarSuccess"
            :before-upload="beforeAvatarUpload"
          >
            <!-- 这两种都是后端做了处理返回的，还有一种就是前端自己拿服务器地址拼接, 然后用 startsWith 判断是不是http开头 如果是的话就不做处理 不是则拼接 -->
            <img
              v-if="userData.avatarURL"
              :src="baseURL + userData.avatarURL"
              class="avatar"
            />
            <!-- <img v-if="userData.avatarURL" :src="userData.avatarURL" class="avatar" /> -->
            <img v-else src="../../assets/common/user.png" class="avatar" />
          </el-upload>
        </el-form-item>
        <el-form-item label="账号名" prop="username">
          <el-input
            v-model="userData.name"
            prefix-icon="el-icon-user"
          ></el-input>
        </el-form-item>
        <el-form-item label="用户名" prop="username">
          <el-input
            v-model="userData.username"
            prefix-icon="el-icon-user"
          ></el-input>
        </el-form-item>
        <el-form-item label="邮箱" prop="email">
          <el-input
            v-model="userData.email"
            prefix-icon="el-icon-message"
          ></el-input>
        </el-form-item>
        <el-form-item label="手机" prop="phone">
          <el-input
            v-model="userData.phone"
            prefix-icon="el-icon-phone"
          ></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input
            type="password"
            v-model="userData.password"
            prefix-icon="el-icon-lock"
          ></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="close">取 消</el-button>
        <el-button type="primary" @click="addUser">确 定 </el-button>
      </span>
    </el-dialog>
    <!-- 分配角色对话框 -->
    <el-dialog
      title="分配角色"
      :visible.sync="roleDialogVisible"
      width="30%"
      @close="closeRole"
    >
      <el-form ref="formRole" :model="currentUser" label-width="70px">
        <el-form-item label="当前用户">
          <el-input
            v-model="currentUser.username"
            prefix-icon="el-icon-user"
            disabled
          ></el-input>
        </el-form-item>
        <el-form-item label="当前角色">
          <el-input
            v-model="currentUserRole"
            prefix-icon="el-icon-user"
            disabled
          ></el-input>
        </el-form-item>
        <el-form-item label="新的角色">
          <el-select
            v-model="currentRoleId"
            @focus="roleList"
            placeholder="请选择角色"
          >
            <el-option
              v-for="item in roles"
              :key="item.id"
              :label="item.roleName"
              :value="item.id"
            >
            </el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="roleDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="submit(currentUser.id)"
          >确 定</el-button
        >
        <el-button type="danger" @click="del(currentUser.id)">删 除</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script lang="ts">
import {
  addUsers,
  createUserRole,
  delUserRole,
  delUsers,
  getAllRoles,
  getOneUserInfo,
  getUserPage,
  updateUsers,
} from "@/api";
import { ElForm } from "element-ui/types/form";
import { Component, Ref, Vue } from "vue-property-decorator";
import XLSX from "xlsx";
import { saveAs } from "file-saver";
import axios from '@/api/network'

interface userData {
  name: string;
  username: string;
  email: string;
  phone: string;
  password: string;
  id: string;
  avatarURL: string;
}

interface searchData {
  role: string;
  origin: string;
  type: string;
  key: string;
  currentPage: number;
  pageSize: number;
}

@Component({
  name: "User",
  components: {},
})
export default class User extends Vue {
  private baseURL:any = ''
  private userData: userData = {
    name: "",
    username: "",
    email: "",
    phone: "",
    password: "",
    id: "",
    avatarURL: "",
  };
  private tableData: any[] = []; //用户列表
  private dialogVisible = false; // 新增和编辑对话框
  private roleDialogVisible = false; // 角色对话框
  private searchData: searchData = {
    role: "", // 角色
    origin: "", // 来源
    type: "", // 用户
    key: "", // 关键字
    currentPage: 1, // 当前页
    pageSize: 5, // 页容量
  };
  private total: number = 0; // 总条数
  private validateName = (rule: any, value: string, callback: any) => {
    const reg = /^[A-Za-z0-9]{6,}$/;
    if (!value) {
      callback(new Error("请填写用户名"));
    } else if (value.length < 6) {
      callback(new Error("用户名至少是6位"));
    } else if (!reg.test(value)) {
      callback(new Error("用户名只能是字母和数字"));
    } else {
      callback();
    }
  };
  private validatePass = (rule: any, value: string, callback: any) => {
    const reg =
      /^(?:(?=.*[0-9].*)(?=.*[A-Za-z].*)(?=.*[,\.#%'\+\*\-:;^_`].*))[,\.#%'\+\*\-:;^_`0-9A-Za-z]{8,}$/;
    if (!value) {
      callback(new Error("请填写密码"));
    } else if (value.length < 6) {
      callback(new Error("密码至少是8位"));
    } else if (!reg.test(value)) {
      callback(new Error("密码必须包含字母数字和特殊符号"));
    } else {
      callback();
    }
  };
  private validateEmail = (rule: any, value: string, callback: any) => {
    const reg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
    if (value && !reg.test(value)) {
      callback(new Error("邮箱格式不正确"));
    } else {
      callback();
    }
  };
  private validatePhone = (rule: any, value: string, callback: any) => {
    const reg = /^1[3456789]\d{9}$/;
    if (value && !reg.test(value)) {
      callback(new Error("手机格式不正确"));
    } else {
      callback();
    }
  };
  // 校验规则
  private userRules: any = {
    username: [{ validator: this.validateName, trigger: "blur" }],
    password: [{ validator: this.validatePass, trigger: "blur" }],
    email: [{ validator: this.validateEmail, trigger: "blur" }],
    phone: [{ validator: this.validatePhone, trigger: "blur" }],
  };
  // 分配角色
  private currentUser: any = {}; // 用户信息
  private roles: any[] = []; // 所有角色
  private currentRoleId = "";

  private addRole(row: any) {
    this.roleDialogVisible = true;
    console.log(row);
    // 当前点击的用户信息
    this.currentUser = row;
    // 这里有个问题 重新打开重置不了
    this.roles = [];
    this.roles.sort();
  }
  // 下拉菜单
  private async roleList() {
    // 分配角色中的下拉菜单
    let result: any = await getAllRoles();
    // console.log(result);
    this.roles = result.data.data;
  }
  // 分配角色确定按钮
  private submit(userId: string) {
    this.roleDialogVisible = false;
    // select绑定了currentRoleId 选中后会赋值给它
    console.log(userId, this.currentRoleId);
    // 分配角色
    const obj = { userId: userId, roleId: this.currentRoleId };
    createUserRole(obj)
      .then((response: any) => {
        // console.log(response);
        if (response.status === 200) {
          this.getUserPage();
          (this as any).$message.success("分配角色成功");
        } else {
          (this as any).$message.error("分配角色失败");
        }
      })
      .catch((e) => {
        (this as any).$message.error(e.response.data.msg);
      });
  }

  // 显示角色名称
  private getCurrentRoleName(row: any) {
    // console.log(row);
    const roles = row.roles;
    const names: any[] = [];
    roles.forEach((item: any) => {
      names.push(item.roleName);
    });
    return names.join(" | ");
  }

  // 计算属性回显拥有角色
  private get currentUserRole() {
    // console.log(JSON.stringify(this.currentUser));
    // 判断是不是空对象
    if (JSON.stringify(this.currentUser) === "{}") return "";
    return this.getCurrentRoleName(this.currentUser);
  }

  // 删除角色
  private del(userId: string) {
    // console.log(userId, this.currentRoleId);
    delUserRole(userId, { roleId: this.currentRoleId })
      .then((response: any) => {
        // console.log(response);
        if (response.status === 200) {
          this.getUserPage();
          this.roleDialogVisible = false;
          (this as any).$message.success("删除角色成功");
        } else {
          (this as any).$message.error("删除角色失败");
        }
      })
      .catch((e) => {
        (this as any).$message.error(e.response.data.msg);
      });
  }

  // 查询
  private onSubmit() {
    this.getUserPage();
  }
  // 字典
  private headerData: any = {
    名称: "name",
    用户账户: "username",
    邮箱: "email",
    电话: "phone",
    状态: "userState",
    第三方平台: "github",
    本地: "local",
    图片地址: "avatarURL",
  };
  // 导出搜索结果
  private exportUser() {
    const data: any[] = [];
    const header = Object.keys(this.headerData);
    // 得到第一行的标题
    data.push(header);
    const users: any = this.tableData.length ? this.tableData : null;
    if (users) {
      users.forEach((item: any) => {
        const temp: any[] = [];
        header.forEach((key: any) => {
          // 将每一行的值都放到一个数组里面
          temp.push(item[this.headerData[key]]);
        });
        // console.log(temp);
        // 将放置好值的数组都放到大数组data中
        data.push(temp);
      });
    }
    // console.log(data);
    // 1.根据二维数组生成表格中的数据
    const sheet = XLSX.utils.aoa_to_sheet(data);
    // 2.创建一个新的表格
    const workbook = XLSX.utils.book_new();
    // 3.把数据添加到表格中,并给这个表格起一个名称
    XLSX.utils.book_append_sheet(workbook, sheet, "user");
    // 4.将生成好的表格保存到本地
    // XLSX.writeFile(workbook, 'users.xlsx'); // 有兼容问题
    const wopts: any = { bookType: "xlsx", bookSST: false, type: "array" };
    const wbout = XLSX.write(workbook, wopts);
    saveAs(
      new Blob([wbout], {
        type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      }),
      "users.xlsx"
    );
  }
  // 添加用户
  @Ref() readonly formData!: ElForm;
  // 打开弹窗
  private showDialog() {
    this.dialogVisible = true;
    // 让弹窗出来后在去重置 使用@$nextTick
    this.$nextTick(() => {
      // 重置表单
      this.formData.resetFields();
    });
  }
  // 添加用户
  private addUser() {
    // 校验通过则发送请求添加用户
    this.formData.validate((valid: boolean) => {
      if (valid) {
        if (!this.userData.id) {
          console.log(this.userData);
          addUsers(this.userData)
            .then((response: any) => {
              // console.log(response);
              const res = response.data.data;
              // 这里有个ts坑点,在往数组追加内容时候,要先定义好这个数组的类型
              // private tableData:any[] = [];
              // this.tableData.push(res);
              this.getUserPage();
              (this as any).$message.success("添加成功");
            })
            .catch((e) => {
              (this as any).$message.error(e.response.data.msg);
            });
        } else {
          // 编辑用户
          updateUsers(this.userData.id, this.userData)
            .then((response: any) => {
              console.log(response);
              this.getUserPage();
              (this as any).$message.success("更新用户成功");
            })
            .catch((e) => {
              (this as any).$message.error(e.response.data.msg);
            });
        }
        this.dialogVisible = false;
      } else {
        (this as any).$message.error("数据格式不正确");
      }
    });
  }
  // 打开编辑弹窗
  private showUser(id: any) {
    // 回显数据
    getOneUserInfo(id).then((response: any) => {
      // console.log(response);
      this.dialogVisible = true;
      // 让弹窗出来后在去赋值
      this.$nextTick(() => {
        this.userData = response.data.data;
      });
    });
  }
  // 删除用户
  private deleteUser(id: string) {
    (this as any)
      .$confirm("确定删除该用户吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
      .then(() => {
        delUsers(id)
          .then((response: any) => {
            // 当前页如果剩下一条数据且页码大于1 则让页码减1
            if (
              this.tableData.length === 1 &&
              this.searchData.currentPage > 1
            ) {
              this.searchData.currentPage--;
            }
            // 刷新用户列表
            this.getUserPage();
          })
          .catch((e) => {
            (this as any).$message.error(e.response.data.msg);
          });
        (this as any).$message({
          type: "success",
          message: "删除成功!",
        });
      })
      .catch(() => {
        (this as any).$message({
          type: "info",
          message: "已取消删除",
        });
      });
  }
  // 导入用户
  private importUser() {}
  // 清空左侧菜单操作
  private resetDefaultActivePath() {
    // 点击首页删除本地储存的菜单地址
    sessionStorage.removeItem("activePath");
  }
  created(): void {
    this.getUserPage();
    // console.log(axios);
    this.baseURL = axios.axios.defaults.baseURL
  }
  // 获取所有用户列表
  private getUserPage() {
    getUserPage(this.searchData)
      .then((response: any) => {
        // console.log(response.status);
        // console.log(response.data);
        if (response.status === 200) {
          // console.log(response.data.data);
          this.tableData = response.data.data.users;
          this.total = response.data.data.count;
        } else {
          (this as any).$message.error(response.data.msg);
        }
      })
      .catch((error) => {
        (this as any).$message.error('获取用户列表失败');
      });
  }
  // 状态按钮更新
  private changeUserState(row: any) {
    // console.log(row);
    updateUsers(row.id, row)
      .then((response: any) => {
        if (response.status === 200) {
          this.getUserPage();
          (this as any).$message.success("更新用户状态成功");
        } else {
          row.userState = !row.userState;
          (this as any).$message.error("更新用户状态失败");
        }
      })
      .catch((e) => {
        row.userState = !row.userState;
        (this as any).$message.error("更新用户状态失败");
      });
  }
  // 头像上传成功回调
  handleAvatarSuccess(res: any, file: any) {
    console.log(res, file);
    if (res.code === 200) {
      this.userData.avatarURL = res.data;
    }
    // this.userData.avatarURL = URL.createObjectURL(file.raw);
  }
  // 头像上传之前的回调
  beforeAvatarUpload(file: any) {
    const whitelist = ["image/jpeg", "image/png"];
    let isIMG;
    whitelist.forEach((item) => {
      isIMG = file.type === item;
    });
    const isLt2M = file.size / 1024 / 1024 < 2;

    if (!isIMG) {
      (this as any).$message.error("上传头像图片只能是 JPG 格式!");
    }
    if (!isLt2M) {
      (this as any).$message.error("上传头像图片大小不能超过 2MB!");
    }
    return isIMG && isLt2M;
  }
  // Excel上传成功回调
  handleExcelSuccess(res: any, file: any) {
    console.log(res, file);
    if (res.code === 200) {
      this.getUserPage();
      (this as any).$message.success("导入用户成功");
    }
    // this.userData.avatarURL = URL.createObjectURL(file.raw);
  }
  // Excel上传之前的回调
  beforeExcelUpload(file: any) {
    // console.log(file);
    const isXls =
      file.type ===
      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    const isLt2M = file.size / 1024 / 1024 < 2;

    if (!isXls) {
      (this as any).$message.error("只能上传Excel文件");
    }
    if (!isLt2M) {
      (this as any).$message.error("上传头像图片大小不能超过 2MB!");
    }
    return isXls && isLt2M;
  }
  // 分页相关操作
  private handleCurrentChange(current: any) {
    // console.log(current);
    this.searchData.currentPage = current;
    this.getUserPage();
  }
  private handleSizeChange(size: any) {
    // console.log(size);
    this.searchData.pageSize = size;
    this.getUserPage();
  }
  // 关闭弹窗
  private close() {
    // 这里有个问题 和人资的那个比较 重置清空表单数据
    this.userData = {
      name: "",
      username: "",
      email: "",
      phone: "",
      password: "",
      id: "",
      avatarURL: "",
    };
    this.dialogVisible = false;
    this.formData.resetFields();
  }
  // 关闭角色弹窗
  private closeRole() {
    this.roleDialogVisible = false;
  }
}
</script>

<style lang="scss" scoped>
.box-card {
  margin-top: 20px;
}
.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  display: inline-block;
  img {
    margin-right: 25px;
  }
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  line-height: 178px;
  text-align: center;
}
.avatar {
  width: 178px;
  height: 178px;
  display: block;
}
.upload-demo {
  display: inline-block;
  margin-left: 20px;
}
</style>